﻿using NexTrackDesktop.NexTrack;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using Moq;
using System.Collections.Generic;
using NexTrackDesktop.Media;

namespace NexTrackDesktopTest
{
    
    
    /// <summary>
    ///This is a test class for ClientTest and is intended
    ///to contain all ClientTest Unit Tests
    ///</summary>
    [TestClass()]
    public class ClientTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///A test for LoadParty
        ///</summary>
        [TestMethod()]
        public void LoadPartyTest()
        {
            var mAdapter = new Mock<MainServiceAdapter>();
            mAdapter.Setup(m => m.GetQueue()).Returns(new List<QueueItem>());

            Client target = new Client(mAdapter.Object);

            bool partyStarted = false;
            target.PartyLoaded += () => { partyStarted = true; };

            target.LoadParty("12345", "Test", "999");

            //The created party object must match
            Assert.AreEqual("12345", target.Party.PartyID);
            Assert.AreEqual("Test", target.Party.Description);
            Assert.AreEqual("999", target.Party.AccessCode);

            //partyStarted is modified above when the PartyLoaded event is ran.
            Assert.IsTrue(partyStarted);
        }

        /// <summary>
        ///A test for NextSong
        ///</summary>
        [TestMethod()]
        public void NextSongTest()
        {
            Mock<MainServiceAdapter> mAdapter;
            Mock<Queue> mQueue;
            Mock<NexTrackPlayer> mPlayer;
            Song testSong;
            Client_Accessor target;
            SetupNextSong(out mAdapter, out mQueue, out mPlayer, out testSong, out target);
            
            target.NextSong();

            verifyNextSong(mAdapter, mQueue, mPlayer, testSong);
        }

        private static void verifyNextSong(Mock<MainServiceAdapter> mAdapter, Mock<Queue> mQueue, Mock<NexTrackPlayer> mPlayer, Song testSong)
        {
            try
            {
                mAdapter.Verify(m => m.GetNextSong());
                mQueue.Verify(m => m.UpdateQueue());
                mPlayer.VerifySet(m => m.NowPlaying = testSong);
            }
            catch (MockException me)
            {
                Assert.Fail(me.Message);
            }
        }

        private static void SetupNextSong(out Mock<MainServiceAdapter> mAdapter, out Mock<Queue> mQueue, out Mock<NexTrackPlayer> mPlayer, out Song testSong, out Client_Accessor target)
        {
            mAdapter = new Mock<MainServiceAdapter>();
            var mParty = new Mock<IParty>();
            mQueue = new Mock<Queue>();
            mPlayer = new Mock<NexTrackPlayer>();
            testSong = new Song() { SongID = "TestSong" };

            mAdapter.Setup(m => m.GetNextSong())
                .Returns(testSong)
                .Verifiable();

            mQueue.Setup(m => m.UpdateQueue())
                .Verifiable();

            mParty.Setup(m => m.Queue)
                .Returns(mQueue.Object);

            target = new Client_Accessor(mAdapter.Object);

            target.Party = mParty.Object;
            target.Player = mPlayer.Object;
        }

        private static void SetupNextSong(out Mock<MainServiceAdapter> mAdapter, out Mock<Queue> mQueue, out Mock<NexTrackPlayer> mPlayer, out Song testSong, out Client target)
        {
            mAdapter = new Mock<MainServiceAdapter>();
            var mParty = new Mock<IParty>();
            mQueue = new Mock<Queue>();
            mPlayer = new Mock<NexTrackPlayer>();
            testSong = new Song() { SongID = "TestSong" };

            mAdapter.Setup(m => m.GetNextSong())
                .Returns(testSong)
                .Verifiable();

            mQueue.Setup(m => m.UpdateQueue())
                .Verifiable();

            mParty.Setup(m => m.Queue)
                .Returns(mQueue.Object);

            target = new Client(mAdapter.Object);

            target.Party = mParty.Object;
            target.Player = mPlayer.Object;
        }

        /// <summary>
        ///A test for Player_MediaEnded
        ///</summary>
        [TestMethod()]
        [DeploymentItem("NexTrackDesktop.exe")]
        public void Player_MediaEndedTest()
        {
            Mock<MainServiceAdapter> mAdapter;
            Mock<Queue> mQueue;
            Mock<NexTrackPlayer> mPlayer;
            Song testSong;
            Client_Accessor target;
            SetupNextSong(out mAdapter, out mQueue, out mPlayer, out testSong, out target);

            target.Player_MediaEnded();

            verifyNextSong(mAdapter, mQueue, mPlayer, testSong);
        }

        /// <summary>
        ///A test for StartMusic
        ///</summary>
        [TestMethod()]
        public void StartMusicTest()
        {
            Mock<MainServiceAdapter> mAdapter;
            Mock<Queue> mQueue;
            Mock<NexTrackPlayer> mPlayer;
            Song testSong;
            Client target;
            SetupNextSong(out mAdapter, out mQueue, out mPlayer, out testSong, out target);

            bool musicStarted = false;

            ((Client)target).MusicStarting += () => { musicStarted = true; };
            target.StartMusic();

            Assert.IsTrue(musicStarted);
            verifyNextSong(mAdapter, mQueue, mPlayer, testSong);
        }
    }
}
